#include "Camera.h"
#include "D3DApp.h"
#include "D3DInput.h"
#include "FrameCalculator.h"
#include "ObObject.h"
#include "ObBackground.h"
#include "StartScene.h"
#include "MapScene.h"
#include "PauseScene.h"
#include "ScoreScene.h"
#include "vector"
#include "NameScene.h"
#include "LoadingScene.h"
#include <stdio.h>
#include "dxaudio.h"

class Mario : public D3DApp{
public:
	Mario(HINSTANCE hInstance, std::string winCaption, D3DDEVTYPE devType, DWORD requestedVP);
	~Mario();

	bool checkDeviceCaps();
	void onLostDevice();
	void onResetDevice();
	void updateScene(float dt);
	void drawScene();

	bool exists_test(const std::string& name);
	void runNextMap(int life, int score, int state);
	void runMap(std::string name, int life, int score, int state);
	void loadMap(std::string name);
private:
	ID3DXSprite* mSprite;
	IDirect3DTexture9* mBackTex;

	std::vector<string> runningmaps;
	std::string currentMap;
	float delay;

	FrameCalculator* calculator;
	Scene* mCurrentScene;
	MapScene* mMapScene;
	StartScene* mStartScene;
	PauseScene* mPauseScene;
	ScoreScene* mScoreScene;
	NameScene* mNameScene;
	LoadingScene* mLoadingScene;
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd){

	Camera	camera;
	gCamera = &camera;

	Mario	app(hInstance,"Mario - 10520254",D3DDEVTYPE_HAL,D3DCREATE_HARDWARE_VERTEXPROCESSING);
	gApp	= &app;

	D3DInput input (DISCL_NONEXCLUSIVE|DISCL_FOREGROUND, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND);
	gInput	= &input;

	if (!Init_DirectSound(gApp->getMainWnd()))
    {
        MessageBox(gApp->getMainWnd(), "Error initializing DirectSound", "Error", MB_OK);
        return 0;
    }

	return gApp->run();
}

Mario::Mario(HINSTANCE hInstance, std::string winCaption, D3DDEVTYPE devType, DWORD requestedVP)
:D3DApp(hInstance,winCaption,devType,requestedVP){
	if(!checkDeviceCaps()){
		MessageBox(0, "checkDeviceCaps() Failed", 0, 0);
		PostQuitMessage(0);
	}

	//backgroundload
	mBackTex = 0;
	D3DXCreateTextureFromFileEx(gDevice,"Sprites/Background.jpg",
		D3DX_DEFAULT_NONPOW2,
		D3DX_DEFAULT_NONPOW2,
		0,
		0,
		D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		D3DCOLOR_XRGB(0,0,0),
		NULL,
		NULL,
		&mBackTex);
	//

	calculator = new FrameCalculator();
	HR(D3DXCreateSprite(gDevice,&mSprite));
	delay = 0.0f;
	mStartScene		= new StartScene(mBackTex);
	mPauseScene		= new PauseScene(mBackTex);
	mScoreScene		= new ScoreScene(mBackTex);
	mNameScene		= new NameScene(mBackTex);
	mLoadingScene	= new LoadingScene(mBackTex);

	currentMap		= "";
	mCurrentScene	= mStartScene;
	mMapScene		= NULL;
	gMapScene		= mMapScene;
	runningmaps.clear();

	onResetDevice();
}

Mario::~Mario(){
	ReleaseCOM(mSprite);
	delete calculator;

	mCurrentScene = NULL;
	if(mStartScene != NULL){
		mStartScene->releaseTexture();
		delete mStartScene;
	}
	if(mMapScene != NULL){
		mMapScene->releaseTexture();
		delete mMapScene;
	}
	if(mPauseScene != NULL){
		mPauseScene->releaseTexture();
		delete mPauseScene;
	}

	if(mScoreScene != NULL){
		mScoreScene->releaseTexture();
		delete mScoreScene;
	}
	
	if(mLoadingScene != NULL){
		mLoadingScene->releaseTexture();
		delete mLoadingScene;
	}

	if(mNameScene != NULL){
		mNameScene->releaseTexture();
		delete mNameScene;
	}

	if(mBackTex != NULL){
		mBackTex->Release();
		mBackTex = NULL;
	}


}

bool Mario::checkDeviceCaps(){
	return true;
}

void Mario::onLostDevice(){
	calculator->onLostDevice();
	HR(mSprite->OnLostDevice());
	mStartScene->onLostDevice();
	mPauseScene->onLostDevice();
	mScoreScene->onLostDevice();
	mNameScene->onLostDevice();
	mLoadingScene->onLostDevice();
	if(mMapScene != NULL){
		mMapScene->onLostDevice();
	}
}

void Mario::onResetDevice(){
	calculator->onResetDevice();
	HR(mSprite->OnResetDevice());
	mStartScene->onResetDevice();
	mPauseScene->onResetDevice();
	mScoreScene->onResetDevice();
	mNameScene->onResetDevice();
	mLoadingScene->onResetDevice();
	if(mMapScene != NULL){
		mMapScene->onResetDevice();
	}
	gCamera->setView();

	RECT rect;
	if(GetWindowRect(this->getMainWnd(), &rect))
	{
		mWidth = (rect.right - rect.left)/2;
		mHeight = (rect.bottom - rect.top)/2;
	}
	gCamera->setLens((float)mWidth, (float)mHeight, -100.0f, 100.0f);

	HR(gDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE));
	HR(gDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE));
	HR(gDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE));

	gDevice->SetRenderState(D3DRS_LIGHTING, false);
	gDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);

	gDevice->SetRenderState(D3DRS_ALPHAREF, 140);
	gDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);

	gDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	gDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

}

void Mario::updateScene(float dt){
	gInput->poll();
	gCamera->update(dt);
	calculator->update(dt);

	if(delay > 0.0f){
		delay -=dt;
		if(delay<= 0.0f){
			delay = 0.0f;
		}
	}
	if(mCurrentScene != NULL){

		SceneRS rs = mCurrentScene->update(dt);
		//update scene here
		if(rs.ID != -1){
			if(StartScene* mstart  = dynamic_cast<StartScene*>(mCurrentScene)){
				switch (rs.ID)
				{
				case 0: //StoryMode
					delay = 0.2f;
					runningmaps.clear();
					if(exists_test("Maps\\StoryMaps\\1.xdmap")){
						runningmaps.push_back("Maps\\StoryMaps\\1.xdmap");
					}
					if(exists_test("Maps\\StoryMaps\\2.xdmap")){
						runningmaps.push_back("Maps\\StoryMaps\\2.xdmap");
					}
					runNextMap(3,0,1);

					break;
				case 1: //LoadMap
					loadMap("Maps\\SavedMap\\SavedMap.xdmap");
					break;
				case 2: //high score
					delay = 0.2f;
					mScoreScene->loadScore();
					mCurrentScene = mScoreScene;
					break;
				}

			}else if(MapScene* mmap  = dynamic_cast<MapScene*>(mCurrentScene)){
				int score = 0, life = 0, state = 0;
				std::string zlife = "", zscore = "", zstate = "";
				unsigned int index;
				switch (rs.ID)
				{
				case 0: //het mang
					score = atoi(rs.Info.c_str());
					mNameScene->setScore(score);
					mCurrentScene = mNameScene;
					break;
				case 1: //con mang
					index = rs.Info.find_first_of(" ");
					zlife =  rs.Info.substr(0,index);
					zscore = rs.Info.substr(index + 1);
					zstate = zlife.substr(0,1);
					zlife = zlife.substr(1);

					life = atoi(zlife.c_str());
					score = atoi(zscore.c_str());
					state = atoi(zstate.c_str());
					runMap(currentMap,life,score, 1);
					break;
				case 2: //win
					index = rs.Info.find_first_of(" ");
					zlife =  rs.Info.substr(0,index);
					zscore = rs.Info.substr(index + 1);
					zstate = zlife.substr(0,1);
					zlife = zlife.substr(1);

					life = atoi(zlife.c_str());
					score = atoi(zscore.c_str());
					state = atoi(zstate.c_str());

					if(runningmaps.size() <= 0){
						mNameScene->setScore(score);
						mCurrentScene = mNameScene;
					}else{
						runNextMap(life,score, state);
					}
					break;
				case 3:
					mCurrentScene = mPauseScene;
					break;
				}
			}else if(PauseScene* mmap  = dynamic_cast<PauseScene*>(mCurrentScene)){
				switch (rs.ID)
				{
				case 0: //resume
					delay = 0.2f;
					mCurrentScene = mMapScene;
					break;
				case 1: //save
					//save 
					delay = 0.4f;
					mMapScene->saveMap();
					break;
				case 2: //back
					delay = 0.2f;
					mCurrentScene = mStartScene;
					mMapScene->releaseTexture();
					delete mMapScene;
					mMapScene = NULL;
					break;
				}
			}else if(ScoreScene* mscore  = dynamic_cast<ScoreScene*>(mCurrentScene)){
				if(rs.ID == 0){
					mCurrentScene = mStartScene;
				}
			}

			else if(NameScene* mname  = dynamic_cast<NameScene*>(mCurrentScene)){
				if(rs.ID == 0){
					mScoreScene->loadScore();
					mCurrentScene = mScoreScene;
				}
			}
		}
	}	
}

void Mario::runNextMap(int life, int score, int state){
	if(runningmaps.size() > 0){
		if(mMapScene != NULL){
			mMapScene->releaseTexture();
			delete mMapScene;
			mMapScene = NULL;
		}
		currentMap = runningmaps[0];
		mLoadingScene->update(0);
		mCurrentScene = mLoadingScene;
		drawScene();
		std::string name = runningmaps[0].substr(runningmaps[0].find_last_of("\\") + 1);
		mMapScene = new MapScene(runningmaps[0], name);
		mMapScene->loading();
		mMapScene->loadTexture();
		runningmaps.erase(runningmaps.begin(),runningmaps.begin() +1);
		gMapScene = mMapScene;
		//
		mMapScene->setSetting(life,score,state);
		//
		mCurrentScene = mMapScene;
	}else{

	}
}

void Mario::runMap(std::string name, int life, int score, int state){
	if(exists_test(name)){
		if(mMapScene != NULL){
			mMapScene->releaseTexture();
			delete mMapScene;
			mMapScene = NULL;
		}
		currentMap = name;
		mCurrentScene = mLoadingScene;
		mLoadingScene->update(0);
		drawScene();
		std::string zname = name.substr(name.find_last_of("\\") + 1);
		mMapScene = new MapScene(name,zname);
		mMapScene->loading();
		mMapScene->loadTexture();
		gMapScene = mMapScene;

		//
		mMapScene->setSetting(life,score,state);
		//
		mCurrentScene = mMapScene;
	}else{
		exit(0);
	}
}

void Mario::loadMap(std::string name){
	if(exists_test(name)){
		
		if(mMapScene != NULL){
			mMapScene->releaseTexture();
			delete mMapScene;
			mMapScene = NULL;
		}
		currentMap = name;
		mCurrentScene = mLoadingScene;
		mLoadingScene->update(0);
		drawScene();
		mMapScene = new MapScene(name,"");
		mMapScene->loading();
		std::string mapName = mMapScene->mMap->getName();
		//mapnext
		runningmaps.clear();
		if(mapName == "1.xdmap" ){
			if(exists_test("Maps\\StoryMaps\\2.xdmap")){
				runningmaps.push_back("Maps\\StoryMaps\\2.xdmap");
			}
			if(exists_test("Maps\\StoryMaps\\3.xdmap")){
				runningmaps.push_back("Maps\\StoryMaps\\3.xdmap");
			}
		}else if(mapName == "2.xdmap"){
			if(exists_test("Maps\\StoryMaps\\3.xdmap")){
				runningmaps.push_back("Maps\\StoryMaps\\3.xdmap");
			}
		}else if(mapName == "3.xdmap"){

		}
		//
		mMapScene->loadTexture();
		gMapScene = mMapScene;
		//
		mCurrentScene = mMapScene;
	}else{
		exit(0);
	}
}

void Mario::drawScene(){
	HR(gDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0));//
	HR(gDevice->BeginScene());
	HR(mSprite->Begin(D3DXSPRITE_OBJECTSPACE |D3DXSPRITE_DONOTMODIFY_RENDERSTATE));// 
	if(mCurrentScene != NULL){
		mCurrentScene->draw(mSprite);
	}
	calculator->draw();
	HR(mSprite->End());
	HR(gDevice->EndScene());
	HR(gDevice->Present(0, 0, 0, 0));
}

bool Mario::exists_test(const std::string& name){
	if (FILE *file = fopen(name.c_str(), "r")) {
        fclose(file);
        return true;
    } else {
        return false;
    }   
}